package com.lin.manager.aop;

import com.alibaba.fastjson2.JSON;
import com.lin.manager.common.enums.LogEnum;
import com.lin.manager.common.resp.R;
import com.lin.manager.common.resp.RespCode;
import com.lin.manager.common.user.UserInfoContextHolder;
import com.lin.manager.common.utils.IPUtils;
import com.lin.manager.system.model.vo.ErrorLogVO;
import com.lin.manager.system.model.vo.OperateLogVO;
import com.lin.manager.system.service.SysErrorLogService;
import com.lin.manager.system.service.SysOperateLogService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Map;
import java.util.Objects;

/**
 * @作者: 林江
 * @创建时间: 2024/3/19
 * @功能:
 */
@Slf4j
@Component
@Aspect
@EnableAspectJAutoProxy
public class LogAspct {
    final ThreadLocal<Long> startTimeThreadLocal = new ThreadLocal();

    @Autowired
    private SysOperateLogService sysOperateLogService;
    @Autowired
    private SysErrorLogService sysErrorLogService;

    @Pointcut("@annotation(com.lin.manager.aop.Log)")
    public void pointcut() {
    }

    @Before("pointcut()")
    public void before(JoinPoint point) {
        log.debug("方法前置通知。。。。。。。。。。");
        startTimeThreadLocal.set(System.currentTimeMillis());
    }

    @AfterReturning(value = "pointcut()", returning = "r")
    public void afterReturn(JoinPoint point, R r) throws Exception {
        log.debug("方法返回通知。。。。。。。。。。");
        OperateLogVO operateLog = new OperateLogVO();
        // 获取业务的执行的时间
        long time = System.currentTimeMillis() - startTimeThreadLocal.get();
        operateLog.setConsumerTime(time);

        MethodSignature signature = (MethodSignature) point.getSignature();
        // 包的全路径
        String clazz = signature.getDeclaringType().getName();
        // 执行方法
        Method method = signature.getMethod();
        String methodName = method.getName();
        operateLog.setCMethod(clazz + "#" + methodName);

        // 日志注解
        Log log = method.getAnnotation(Log.class);
        if (Objects.nonNull(log)) {
            operateLog.setModule(log.module());
            operateLog.setDescript(log.descipt());
            operateLog.setType(log.type().toString());
        }

        // 设置其他属性
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        // 获取当前线程绑定的请求。从获取RequestAttributes中获取HttpServletRequest的信息
        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
        operateLog.setIp(IPUtils.getIpAddr(request));
        operateLog.setReqUri(request.getRequestURI());
        operateLog.setReqMethod(request.getMethod());
        operateLog.setRespParams(JSON.toJSONString(r.getData()));
        operateLog.setUserName(UserInfoContextHolder.getUserName());
        operateLog.setCreateTime(new Date());
        // 请求参数
        Map<String, String[]> parameterMap = request.getParameterMap();
        if (parameterMap.size() > 0) {
            operateLog.setReqParams(JSON.toJSONString(parameterMap));
        } else {
            if (!operateLog.getType().equals(LogEnum.FILE.toString())) {
                operateLog.setReqParams(JSON.toJSONString(point.getArgs()));
            }
        }

        // 其他属性
//        String header = request.getHeader("User-Agent");
//        UserAgent userAgent = UserAgent.parseUserAgentString(header);
//        String name = userAgent.getBrowser().getName();
//        userAgent.getOperatingSystem().getName();
//        IPUtils.getIpSource(operateLog.getIp());

        sysOperateLogService.addLog(operateLog);
    }


    // 异常通知
    @AfterThrowing(value = "pointcut()", throwing = "e")
    public void afterThrowing(JoinPoint point, RuntimeException e) {
        log.debug("方法异常通知。。。。。。。。。。", e);
        ErrorLogVO errorLog = new ErrorLogVO();
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        // 获取当前线程绑定的请求。从获取RequestAttributes中获取HttpServletRequest的信息
        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
        errorLog.setIp(IPUtils.getIpAddr(request));
        errorLog.setReqUri(request.getRequestURI());
        errorLog.setReqMethod(request.getMethod());
        errorLog.setUserName(UserInfoContextHolder.getUserName());
        errorLog.setCreateTime(new Date());
        errorLog.setEMsg(e.toString());
        if (Objects.isNull(e.getMessage())) {
            errorLog.setECode("空指针异常");
        } else {
            errorLog.setECode(e.getMessage().length() > 200 ? RespCode.PARAMS.getMsg() : e.getMessage());
        }

        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        Log log = method.getAnnotation(Log.class);
        if (Objects.nonNull(log)) {
            errorLog.setModule(log.module());
            errorLog.setDescript(log.descipt());
        }

        // 请求参数
        Map<String, String[]> parameterMap = request.getParameterMap();
        if (parameterMap.size() > 0) {
            errorLog.setReqParams(JSON.toJSONString(parameterMap));
        } else {
            if (!log.type().toString().equals(LogEnum.FILE.toString())) {
                errorLog.setReqParams(JSON.toJSONString(point.getArgs()));
            }
        }

        sysErrorLogService.addLog(errorLog);
    }

    @After("pointcut()")
    public void after() {
        log.debug("返回通知。。。。。。。。。。");
        startTimeThreadLocal.remove();
    }
}
